#include "../parser.tab.hpp"
#include "../ast.h"
#include "../ir.h"
#include "../reg_alloc.h"
#include "../code.h"
#include "../ir_optimizer.h"
#include "../dead_code_elimination.h"
#include "../code_peephole.h"
#include <filesystem>
#include <cstdio>
#include <fstream>
#include <string>
using namespace ast;
using namespace ir;
using namespace reg_alloc;
using namespace dead_code_elimination;
using namespace std;
using namespace filesystem;
using namespace code;

extern FILE* yyin;
extern int yyparse(unique_ptr<BaseAST>& root);

static void output(string file_path, string result)
{
    ofstream out(file_path);
    out << result;
    out.close();
}

int main()
{
    remove_all("output");
    create_directory("output");
    for (auto& entry : directory_iterator("input"))
    {   
        // 词法分析和语法分析
        const char* input_file_path = entry.path().c_str();
        yyin = fopen(input_file_path, "r");
        unique_ptr<BaseAST> root;
        yyparse(root);
        fclose(yyin);
        CompUnitAST* comp_unit = dynamic_cast<ast::CompUnitAST*>(root.get());

        // 按步骤生成代码
        IR ir = IRGenerator().Generate(*comp_unit);
        IR const_propagated_ir = ir;
        ir::Optimizer::Optimize(const_propagated_ir);
        IR dead_code_eliminated_ir = 
                DeadCodeEliminator().Optimize(const_propagated_ir);
        IR reg_alloc_ir;
        for (ir::Function& func : dead_code_eliminated_ir.funcs)
        {
            ir::Function new_func = move(RegAllocator().Allocate(func));
            reg_alloc_ir.funcs.push_back(move(new_func));
        }
        code::Code code = code::CodeGenerator().Generate(reg_alloc_ir);
        Code optimized_code = code;
        code::peephole_optimizer::peephole_optimize(optimized_code);

        // 输出各步骤的结果
        string output_dir_path = "output/" + entry.path().stem().string();
        create_directories(output_dir_path);
        string output_file_path_1 = output_dir_path + "/step1(ir).txt";
        output(output_file_path_1, ir.ToString());
        string output_file_path_2 = output_dir_path + "/step2(const propagation).txt";
        output(output_file_path_2, const_propagated_ir.ToString());
        string output_file_path_3 = output_dir_path + "/step3(dead code elimination).txt";
        output(output_file_path_3, dead_code_eliminated_ir.ToString());
        string output_file_path_4 = output_dir_path + "/step4(reg_alloc).txt";
        output(output_file_path_4, reg_alloc_ir.ToString());
        string output_file_path_5 = output_dir_path + "/step5(code).s";
        output(output_file_path_5, code.ToString());
    }
    return 0;
}